/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Utilitarios;


import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Betty
 */
public class ManejadorBaseDatos implements Constantes{


    private String descripcionError;
    private Boolean existeError;
    private Connection conexion;
    private ArrayList valorResultado;


    static private ManejadorBaseDatos _Instancia = null;



    static public synchronized ManejadorBaseDatos getInstancia(){
        if (_Instancia == null) {
            _Instancia = new ManejadorBaseDatos();
        }
        return _Instancia;
    }


    private ManejadorBaseDatos() {

        try {
            //el constructor inicializa la conexion, buscando el driver de SQL
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            //y obteniendo la conexion de acuerdo a la constante
            this.conexion = DriverManager.getConnection(URL_CONEXION);
            //no hubo errores
            this.existeError = Boolean.FALSE;
            this.descripcionError = "";
        }
        catch (SQLException exc) {
            //si sucede alguna excepción de SQL, se registra en el log de Glassfish y no se muestra en interfaz el detalle
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Excepción SQL al realizar la conexión con la Base de Datos", exc);
            //hubo error
            this.existeError = Boolean.TRUE;
            //se establece la descripción del error
            this.descripcionError = "Error en la Conexión con la Base de Datos";
        }
        catch (ClassNotFoundException exc) {
            //si sucede alguna excepción al buscar el driver de SQL, se registra en el log de Glassfish y no se muestra en interfaz
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Excepción SQL al buscar el manejador de conexión con la Base de Datos", exc);
            //hubo error
            this.existeError = Boolean.TRUE;
            //se establece la descripción del error
            this.descripcionError = "Excepción SQL al buscar el manejador de conexión con la Base de Datos";
        }
    }


    /**
     * Método que realiza una consulta SELECT a la base de datos
     * @param query: consulta SELECT a ejecutar
     * @return True: si tuvo exito; False en caso contrario
     */
    public Boolean cargarConsulta(String query) {

        try {

            Statement statement;
            ResultSet resultSet;

            //se crea el statement
            statement = this.conexion.createStatement();
            //y se ejecuta la consulta
            resultSet = statement.executeQuery(query);

            //lista donde se almacenan las filas
            ArrayList listaFilas = new ArrayList();
            //se obtienen los metadatos de la consulta
            ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
            //y de ahi se obtienen la cantidad de columnas
            int cantidadColumnas = resultSetMetaData.getColumnCount();
            //mientras haya filas por recorrer mediante el cursor
            while(resultSet.next()) {
                //se crea una lista de valores para la fila actual en proceso
                ArrayList unaFila = new ArrayList();
                //para cada columna de la fila en proceso
                for(int i = 1; i <= cantidadColumnas; i++) {
                    //se obtiene el valor
                    String unValor = resultSet.getString(i);
                    //y se agrega a la lista de valores para la fila
                    unaFila.add(unValor);
                }
                //se añade la fila a la lista de filas
                listaFilas.add(unaFila);
            }
            //no hay error
            this.existeError = Boolean.FALSE;
            //se establece el valor del resultado
            this.valorResultado = listaFilas;
            //retorna TRUE
            return Boolean.TRUE;
        }
        catch (SQLException exc) {
            //si hubo alguna excepción SQL en la consulta, se registra en el log de Glassfish y no se muestra en interfaz el detalle
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Excepción SQL al realizar una consulta SELECT en la Base de Datos", exc);
            //hubo error
            this.existeError = Boolean.TRUE;
            //se establece la descripción del error
            this.descripcionError = "Error en la consulta a la Base de Datos";
            //retorna FALSE
            return Boolean.FALSE;
        }


    }

    /**
     * Método que ejecuta un stored procedure de la base de datos
     */
     public boolean ejecutarSP2(String storedProcedure, ArrayList parametros)
    {
        CallableStatement cs = null;
        try
        {
            String llamada = construirLlamada(storedProcedure, parametros);
            cs = this.conexion.prepareCall(llamada);

            for(int indice = 0; indice < parametros.size(); indice++)
            {
//                 System.out.println("PARAM: " + parametros.get(indice));
                // cs.setObject(indice, parametros.get(indice));
                 cs.setObject(indice+1, parametros.get(indice));

            }
            cs.execute();

            this.existeError = Boolean.FALSE;
            return Boolean.TRUE;
        }
        catch (SQLException exc)
        {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Excepción SQL al ejecutar un Stored Procedure", exc);
            this.existeError = Boolean.TRUE;
            this.descripcionError = "Error en la consulta a la Base de Datos";
            return Boolean.FALSE;
        }
    }

    /**
     * Método que ejecuta un stored procedure de la base de datos
     */
     public boolean ejecutarSP(String storedProcedure, ArrayList parametros)
    {
        CallableStatement cs = null;
        ArrayList listaFilas = new ArrayList();
        ResultSet resultSet;
        try
        {
            String llamada = construirLlamada(storedProcedure, parametros);
            cs = this.conexion.prepareCall(llamada);

            for(int indice = 0; indice < parametros.size(); indice++)
            {
//                 System.out.println("PARAM: " + parametros.get(indice));
                // cs.setObject(indice, parametros.get(indice));
                 cs.setObject(indice+1, parametros.get(indice));

            }
            cs.execute();
            resultSet = cs.getResultSet();
            ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
            int cantidadColumnas = resultSetMetaData.getColumnCount();
            while(resultSet.next()) {
                ArrayList unaFila = new ArrayList();
                for(int i = 1; i <= cantidadColumnas; i++) {
                    String unValor = resultSet.getString(i);
                    unaFila.add(unValor);
                }
                listaFilas.add(unaFila);
            }
            this.existeError = Boolean.FALSE;
            this.valorResultado = listaFilas;
            return Boolean.TRUE;
        }
        catch (SQLException exc)
        {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Excepción SQL al ejecutar un Stored Procedure", exc);
            this.existeError = Boolean.TRUE;
            this.descripcionError = "Error en la consulta a la Base de Datos";
            return Boolean.FALSE;
        }
    }

    /**
     * Método que construye la llamada del stored procedure
     */
    private String construirLlamada(String storedProcedure, ArrayList parametros)
    {
        String llamada = "{call " + storedProcedure;

        if(!parametros.isEmpty())
        {
            llamada += "(";
            for(int indice = 0; indice < parametros.size(); indice++)
            {
                llamada += "?";
                if ((indice + 1) != parametros.size())
                {
                    llamada += ", ";
                }
                /*else{
                    llamada += parametros.get(indice);
                }*/
            }
            llamada += ")}";
        }
        else
        {
            llamada += "()}";
        }

        System.out.println("LLAMADA: " + llamada);
        return llamada;
    }

    /**
     * @return the descripcionError
     */
    public String getDescripcionError() {
        return descripcionError;
    }

    /**
     * @param descripcionError the descripcionError to set
     */
    public void setDescripcionError(String descripcionError) {
        this.descripcionError = descripcionError;
    }

    /**
     * @return the existeError
     */
    public Boolean getExisteError() {
        return existeError;
    }

    /**
     * @return the valorResultado
     */
    public ArrayList getValorResultado() {
        return valorResultado;
    }

}
